import axios, {AxiosInstance, AxiosRequestConfig, AxiosResponse, InternalAxiosRequestConfig} from 'axios';
import {ElMessage, ElMessageBox} from 'element-plus';
import {CacheManager} from "/@/cache";
import qs from "qs";

// 配置新建一个 axios 实例
const axiosInstance: AxiosInstance = axios.create({
    baseURL: import.meta.env.MODE !== 'production' ? import.meta.env.VITE_BASE_API : import.meta.env.VITE_API_URL,
    timeout: 50000,
    headers: {'Content-Type': 'application/json'},
    paramsSerializer: {
        serialize: function (params: Record<string, any>) {
            return qs.stringify(params, {allowDots: true});
        }
    }
});

// 添加请求拦截器
axiosInstance.interceptors.request.use(
    (config: InternalAxiosRequestConfig) => {
        // 在发送请求之前做些什么 token
        if (CacheManager.getToken()) {
            config.headers['Token'] = `${CacheManager.getToken()}`;
        }
        return config;
    },
    (error: any) => {
        // 对请求错误做些什么
        ElMessage.error(error);
        return Promise.reject(error);
    }
);

// 添加响应拦截器
axiosInstance.interceptors.response.use((response: AxiosResponse) => {
        // 对响应数据做点什么
        const result = response?.data;
        if (result?.code === undefined || result?.code === 200) {
            return response;
        } else {
            let message = result?.message;
            // `token` 过期或者账号已在别处登录
            if (result.code === 401) {
                CacheManager.clearSession()// 清除浏览器全部临时缓存
                ElMessageBox.alert('你已被登出，请重新登录', '提示', {})
                    .then(() => {
                        setTimeout(() => {
                            window.location.href = '/'; // 去登录页
                        }, 300)
                    })
                    .catch(() => {
                    });
            } else {
                ElMessage.error(message);
            }
            return Promise.reject(response);
        }
    },
    (error) => {
        // 对响应错误做点什么
        if (error.message.indexOf('timeout') != -1) {
            ElMessage.error('网络超时');
        } else if (error.message == 'Network Error') {
            ElMessage.error('网络连接错误');
        } else if (error.code === 'ERR_BAD_RESPONSE') {
            ElMessage.error('服务器异常');
        } else {
            ElMessage.error(error.message || error.code);
        }
        return Promise.reject(error);
    }
);

const processResult = <T = any>(response: AxiosResponse<any>): T => {
    const result = response.data
    if (result?.code === undefined) {
        return result;
    } else {
        return result.data;
    }
}

const service = {
    async request<T = any, R = any>(config: AxiosRequestConfig<R>): Promise<T> {
        const axiosResponse = await axiosInstance.request<any, AxiosResponse<any>, R>(config);
        return processResult<T>(axiosResponse);
    },
    async get<T = any, R = any>(url: string, config?: AxiosRequestConfig<R>): Promise<T> {
        const axiosResponse = await axiosInstance.get<any, AxiosResponse<any>, R>(url, config);
        return processResult<T>(axiosResponse);
    },
    async delete<T = any, R = any>(url: string, config?: AxiosRequestConfig<R>): Promise<T> {
        const axiosResponse = await axiosInstance.delete<any, AxiosResponse<any>, R>(url, config);
        return processResult<T>(axiosResponse);
    },
    async head<T = any, R = any>(url: string, config?: AxiosRequestConfig<R>): Promise<T> {
        const axiosResponse = await axiosInstance.head<any, AxiosResponse<any>, R>(url, config);
        return processResult<T>(axiosResponse);
    },
    async options<T = any, R = any>(url: string, config?: AxiosRequestConfig<R>): Promise<T> {
        const axiosResponse = await axiosInstance.options<any, AxiosResponse<any>, R>(url, config);
        return processResult<T>(axiosResponse);
    },
    async post<T = any, R = any>(url: string, data?: R, config?: AxiosRequestConfig<R>): Promise<T> {
        const axiosResponse = await axiosInstance.post<any, AxiosResponse<any>, R>(url, data, config);
        return processResult<T>(axiosResponse);
    },
    async put<T = any, R = any>(url: string, data?: R, config?: AxiosRequestConfig<R>): Promise<T> {
        const axiosResponse = await axiosInstance.put<any, AxiosResponse<any>, R>(url, data, config);
        return processResult<T>(axiosResponse);
    },
    async patch<T = any, R = any>(url: string, data?: R, config?: AxiosRequestConfig<R>): Promise<T> {
        const axiosResponse = await axiosInstance.patch<any, AxiosResponse<any>, R>(url, data, config);
        return processResult<T>(axiosResponse);
    },
    async postForm<T = any, R = any>(url: string, data?: R, config?: AxiosRequestConfig<R>): Promise<T> {
        const axiosResponse = await axiosInstance.postForm<any, AxiosResponse<any>, R>(url, data, config);
        return processResult<T>(axiosResponse);
    },
    async putForm<T = any, R = any>(url: string, data?: R, config?: AxiosRequestConfig<R>): Promise<T> {
        const axiosResponse = await axiosInstance.putForm<any, AxiosResponse<any>, R>(url, data, config);
        return processResult<T>(axiosResponse);
    },
    async patchForm<T = any, R = any>(url: string, data?: R, config?: AxiosRequestConfig<R>): Promise<T> {
        const axiosResponse = await axiosInstance.patchForm<any, AxiosResponse<any>, R>(url, data, config);
        return processResult<T>(axiosResponse);
    },
    //上传文件，Content-Type和超时时间需要单独配置
    async upload<T = any, R = any>(url: string, data?: R, config?: AxiosRequestConfig<R>): Promise<T> {
        const axiosResponse = await axiosInstance.post<any, AxiosResponse<any>, R>(url, data, <AxiosRequestConfig<R>>{
            ...config,
            headers: {'Content-Type': 'multipart/form-data'},
            timeout: 0,
        });
        return processResult<T>(axiosResponse);
    },
}
export default service;
